using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using MotionFramework;
using MotionFramework.Resource;
using MotionFramework.UIKit;
using UnityEngine;
using HybridCLR;

/// <summary>
/// 热更新管理器
/// </summary>
namespace MotionFramework.HybridCLR
{
    public class HotfixManager : ModuleSingleton<HotfixManager>, IModule
    {
        void IModule.OnCreate(object createParam)
        {
            // 检测依赖模块
            if (MotionEngine.Contains(typeof(ResourceManager)) == false)
                throw new Exception($"{nameof(WindowManager)} depends on {nameof(ResourceManager)}");
        }

        void IModule.OnDestroy()
        {
        }

        void IModule.OnGUI()
        {
        }

        void IModule.OnUpdate()
        {
        }

        /// <summary>
        /// 为aot assembly加载原始metadata， 这个代码放aot或者热更新都行。
        /// 一旦加载后，如果AOT泛型函数对应native实现不存在，则自动替换为解释模式执行
        /// </summary>
        public unsafe void LoadMetadataForAOTAssembly(List<string> assemblys)
        {
#if !UNITY_EDITOR
            foreach (var assembly in assemblys)
            {
                var handle = ResourceManager.Instance.LoadAssetSync<TextAsset>(assembly);
                var textAsset = handle.AssetObject as TextAsset;
                if (textAsset != null) 
                {
                    var bytes = textAsset.bytes;
                    fixed (byte* ptr = bytes)
                    {
                        // 加载assembly对应的dll，会自动为它hook。一旦aot泛型函数的native函数不存在，用解释器版本代码
                        var err = RuntimeApi.LoadMetadataForAOTAssembly(ptr, bytes.Length, (int)HomologousImageMode.Consistent);
                        MotionLog.Log($"LoadMetadataForAOTAssembly:{assembly}. ret:{err}");
                    }
                }
            }
#endif
        }

        /// <summary>
        /// 加载热更新动态库
        /// </summary>
        public void LoadAssembly(List<string> assemblys)
        {
#if !UNITY_EDITOR
            try
            {
                foreach (var assembly in assemblys)
                {
                    var handle = ResourceManager.Instance.LoadAssetSync<TextAsset>(assembly);
                    var textAsset = handle.AssetObject as TextAsset;
                    if (textAsset != null) 
                    {
                        var rawAssembly = textAsset.bytes;
                        Assembly.Load(rawAssembly);
                    }
                }                
            }
            catch (Exception e)
            {
                MotionLog.Error(e.ToString());
            }
#endif
        }
    }
}
